--- @param extension Package
--- @param HY HY_Utility
--- @param U Utility
return function(extension, HY, U)
    local hy_houraisan_kaguya = General:new(extension, "hy_houraisan_kaguya", "jin_k", 4, 4, General.Female)
    local time_slice = fk.CreateSkill {
        name = "time_slice",
    }
    time_slice:addEffect(fk.EventPhaseEnd, {
        anim_type = "defensive",
        can_trigger = function(self, event, target, player, data)
            return player:hasSkill(time_slice.name) and target == player and
                (player.phase == Player.Draw or (player.phase == Player.Discard and (player:getMark("@time_slice_draw-turn") ~= 0 or player:getMark("@time_slice_discard-turn") ~= 0)))
        end,
        on_cost = function(self, event, target, player, data)
            local room = player.room
            if player.phase == Player.Draw then
                local result = room:askToChoice(player, {
                    choices = { "time_slice_draw", "time_slice_discard", "Cancel" },
                    skill_name = time_slice.name
                })
                if result == "Cancel" then
                    return false
                elseif result == "time_slice_draw" then
                    event:setCostData(self, room:askToChoice(player, {
                        choices = { "1", "2" },
                        skill_name = time_slice.name
                    }))
                    return true
                else
                    local cards = room:askToCards(player, {
                        min_num = 1,
                        max_num = 2,
                        include_equip = true,
                        skill_name = time_slice.name,
                        cancelable = false,
                        prompt = "time_slice_prompt"
                    })
                    if type(cards) == "number" then
                        cards = { cards }
                    end
                    event:setCostData(self, cards)
                    return true
                end
            else
                return true
            end
        end,
        on_use = function(self, event, target, player, data)
            local room = player.room
            if player.phase == Player.Draw then
                if type(event:getCostData(self)) == "table" then
                    room:throwCard(event:getCostData(self), time_slice.name, player, player)
                    room:setPlayerMark(player, "@time_slice_draw-turn", #event:getCostData(self))
                elseif player and not player.dead then
                    local count = tonumber(event:getCostData(self)) or 0
                    count = math.floor(math.max(0, count))
                    room:drawCards(player, count, time_slice.name)
                    room:setPlayerMark(player, "@time_slice_discard-turn", count)
                end
            else
                local draw = player:getMark("@time_slice_draw-turn")
                local discard = player:getMark("@time_slice_discard-turn")
                if draw > 0 and not player.dead then
                    room:drawCards(player, draw, time_slice.name)
                    local other = room:askToChoosePlayers(player, {
                        targets = room:getOtherPlayers(player),
                        min_num = 1,
                        max_num = 1,
                        prompt = "time_slice_prompt_choose",
                        skill_name = time_slice.name,
                    })
                    if #other > 0 and not other[1].dead then
                        room:drawCards(other[1], 1, time_slice.name)
                    end
                else
                    if #player:getCardIds("he") > discard then
                        room:askToDiscard(player, {
                            min_num = discard,
                            max_num = discard,
                            include_equip = true,
                            skill_name = time_slice.name,
                            cancelable = false
                        })
                    elseif #player:getCardIds("he") == discard then
                        room:throwCard(player:getCardIds("he"), time_slice.name, player, player)
                    else
                        room:loseHp(player, 1, time_slice.name)
                    end
                    if not player.dead then
                        local other = room:askToChoosePlayers(player, {
                            targets = room:getOtherPlayers(player),
                            min_num = 1,
                            max_num = 1,
                            prompt = "time_slice_prompt_choose",
                            skill_name = time_slice.name,
                        })
                        if #other > 0 then
                            local o = other[1]
                            if #o:getCardIds("he") > 1 then
                                room:askToDiscard(o, {
                                    min_num = 1,
                                    max_num = 1,
                                    include_equip = true,
                                    skill_name = time_slice.name,
                                    cancelable = false
                                })
                            elseif #o:getCardIds("he") == 1 then
                                room:throwCard(o:getCardIds("he"), time_slice.name, o, o)
                            else
                                room:loseHp(o, 1, time_slice.name)
                            end
                        end
                    end
                end
            end
        end,
    })
    local night_return = fk.CreateSkill {
        name = "night_return",
    }
    night_return:addEffect(fk.EventPhaseEnd, {
        anim_type = "negative",
        can_trigger = function(self, event, target, player, data)
            if not player:hasSkill(night_return.name) then
                return false
            end
            return player == target and player.phase == Player.Play and #player:getCardIds("h") > 0
        end,
        on_cost = function(self, event, target, player, data)
            local room = player.room
            local targets, cards = room:askToChooseCardsAndPlayers(player, {
                min_card_num = 1,
                max_card_num = 1,
                targets = table.filter(room:getOtherPlayers(player), function(t)
                    return #t:getCardIds("h") > 0
                end),
                min_num = 1,
                max_num = 2,
                pattern = ".|.|.|hand",
                prompt = "night_return_prompt_pindian",
                skill_name = night_return.name,
            })
            event:setCostData(self, { targets, cards })
            return #targets > 0 and #cards > 0
        end,
        on_use = function(self, event, target, player, data)
            local targets = event:getCostData(self)[1]
            local card = Fk:getCardById(event:getCostData(self)[2][1])
            player:pindian(targets, night_return.name, card)
        end,
    })
    night_return:addEffect(fk.PindianFinished, {
        anim_type = "negative",
        can_trigger = function(self, event, target, player, data)
            if not player:hasSkill(night_return.name) then
                return false
            end
            event:setCostData(self, 0)
            for id, struct in pairs(data.results) do
                if struct.winner == data.from then
                    event:setCostData(self, event:getCostData(self) + 1)
                end
            end
            return data.reason == night_return.name and event:getCostData(self) > 0 and (data.fromCard.trueName == "slash" or data.fromCard:isCommonTrick()) and
                player:canUse(Fk:cloneCard(data.fromCard.name), { bypass_times = true })
        end,
        on_cost = function(self, event, target, player, data)
            local room = player.room
            return room:askToSkillInvoke(player, {
                skill_name = night_return.name,
                prompt = "night_return_prompt:::" .. data.fromCard:toLogString() .. ":" .. tostring(event:getCostData(self))
            })
        end,
        on_use = function(self, event, target, player, data)
            local room = player.room
            for i = 1, event:getCostData(self), 1 do
                if not player:canUse(Fk:cloneCard(data.fromCard.name), { bypass_times = true }) then
                    return
                end
                local use = room:askToUseVirtualCard(player, {
                    name = data.fromCard.name,
                    skill_name = night_return.name,
                })
                if use == nil then
                    return
                end
            end
        end,
    })
    local stack_moment = fk.CreateSkill {
        name = "stack_moment",
    }
    stack_moment:addEffect(fk.PindianCardsDisplayed, {
        anim_type = "defensive",
        events = {
            fk.PindianCardsDisplayed,
        },
        can_trigger = function(self, event, target, player, data)
            if not player:hasSkill(stack_moment.name) then
                return false
            end
            local number = math.clamp(player:getMark("@stack_moment"), 1, 13)
            if data.from == player then
                event:setCostData(self, data.fromCard)
            else
                for t, struct in pairs(data.results) do
                    if t == player then
                        event:setCostData(self, struct.toCard)
                    end
                end
            end
            return event:getCostData(self) and event:getCostData(self).number < number
        end,
        on_cost = Util.TrueFunc,
        on_use = function(self, event, target, player, data)
            local number = math.clamp(player:getMark("@stack_moment"), 1, 13)
            event:getCostData(self).number = math.max(event:getCostData(self).number, number)
        end,
    })
    stack_moment:addEffect(fk.GameStart, {
        can_refresh = function(self, event, target, player, data)
            if not player:hasSkill(stack_moment.name) then
                return false
            end
            return true
        end,
        on_refresh = function(self, event, target, player, data)
            player.room:setPlayerMark(player, "@stack_moment", 0)
        end
    })
    stack_moment:addEffect(fk.AfterCardsMove, {
        can_refresh = function(self, event, target, player, data)
            if not player:hasSkill(stack_moment.name) then
                return false
            end
            return #table.filter(data, function(move)
                return move.from == player and table.any(move.moveInfo, function(info)
                    return info.fromArea == Card.PlayerHand or info.fromArea == Card.PlayerEquip
                end)
            end) > 0
        end,
        on_refresh = function(self, event, target, player, data)
            local room = player.room
            local number = player:getMark("@stack_moment")
            for _, move in ipairs(data) do
                if move.from == player then
                    for _, info in ipairs(move.moveInfo) do
                        if info.fromArea == Card.PlayerHand or info.fromArea == Card.PlayerEquip then
                            number = number + 1
                        end
                    end
                end
            end
            if number > 13 then
                number = 13
            end
            room:setPlayerMark(player, "@stack_moment", number)
        end
    })
    extension:loadSkillSkels { time_slice, night_return, stack_moment }
    hy_houraisan_kaguya:addSkill("time_slice")
    hy_houraisan_kaguya:addSkill("night_return")
    hy_houraisan_kaguya:addSkill("stack_moment")
    Fk:loadTranslationTable {
        ["hy_houraisan_kaguya"] = "蓬莱山辉夜",
        ["#hy_houraisan_kaguya"] = "与时隔绝",
        ["illustrator:hy_houraisan_kaguya"] = "小出雲",
        ["designer:hy_houraisan_kaguya"] = "黑曜人形",
        ["cv:hy_houraisan_kaguya"] = "",

        ["time_slice"] = "裂时",
        [":time_slice"] = "摸牌阶段结束时，你可以弃置/摸至多两张牌，若如此做，你于弃牌阶段结束时摸/弃置等量的牌，然后你可以令一名其他角色摸/弃置一张牌（不足则改为失去1点体力）。",
        ["time_slice_draw"] = "摸牌",
        ["time_slice_discard"] = "弃牌",
        ["@time_slice_draw-turn"] = "裂时 摸",
        ["@time_slice_discard-turn"] = "裂时 弃",
        ["time_slice_prompt"] = "裂时：弃置至多两张牌",
        ["time_slice_prompt_choose"] = "裂时：选择一名其他角色",

        ["night_return"] = "夜返",
        [":night_return"] = "出牌阶段结束时，你可以用一张手牌与至多两名角色同时拼点，此拼点结算结束后，若你的拼点牌为【杀】或普通锦囊牌，你可以视为使用X张此牌（X为你赢的次数）。",
        ["night_return_prompt"] = "夜返：你可以视为使用%arg2张%arg",
        ["night_return_prompt_pindian"] = "夜返：你可以使用一张手牌与至多两名角色拼点",

        ["stack_moment"] = "积刻",
        [":stack_moment"] = "你的拼点牌点数视为你于本局游戏失去的牌数与此牌点数中的较大值。",
        ["@stack_moment"] = "积刻",
    }
end
